home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Tools / MPW / gawk 2.11.1r3 / Sources / builtin.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-01  |  20.4 KB  |  1,065 lines  |  [TEXT/MPS ]

  1. /*
  2.  * builtin.c - Builtin functions and various utility procedures 
  3.  */
  4.  
  5. /* 
  6.  * Copyright (C) 1986, 1988, 1989 the Free Software Foundation, Inc.
  7.  * 
  8.  * This file is part of GAWK, the GNU implementation of the
  9.  * AWK Progamming Language.
  10.  * 
  11.  * GAWK is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 1, or (at your option)
  14.  * any later version.
  15.  * 
  16.  * GAWK is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  * 
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with GAWK; see the file COPYING.  If not, write to
  23.  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  24.  */
  25.  
  26. /* 01Jun91    Matthias Neeracher    <neeri@iis.ethz.ch>    MPW port */
  27.  
  28. #include "awk.h"
  29.  
  30. extern void srandom();
  31. extern char *initstate();
  32. extern char *setstate();
  33. extern long random();
  34.  
  35. extern NODE **fields_arr;
  36.  
  37. static void get_one();
  38. static void get_two();
  39. static int get_three();
  40.  
  41. /* Builtin functions */
  42. NODE *
  43. do_exp(tree)
  44. NODE *tree;
  45. {
  46.     NODE *tmp;
  47.     double d, res;
  48.     double exp();
  49.  
  50.     get_one(tree, &tmp);
  51.     d = force_number(tmp);
  52.     free_temp(tmp);
  53.     errno = 0;
  54.     res = exp(d);
  55.     if (errno == ERANGE)
  56.         warning("exp argument %g is out of range", d);
  57.     return tmp_number((AWKNUM) res);
  58. }
  59.  
  60. NODE *
  61. do_index(tree)
  62. NODE *tree;
  63. {
  64.     NODE *s1, *s2;
  65.     register char *p1, *p2;
  66.     register int l1, l2;
  67.     long ret;
  68.  
  69.  
  70.     get_two(tree, &s1, &s2);
  71.     force_string(s1);
  72.     force_string(s2);
  73.     p1 = s1->stptr;
  74.     p2 = s2->stptr;
  75.     l1 = s1->stlen;
  76.     l2 = s2->stlen;
  77.     ret = 0;
  78.     if (! strict && IGNORECASE_node->var_value->numbr != 0.0) {
  79.         while (l1) {
  80.             if (casetable[*p1] == casetable[*p2]
  81.                 && strncasecmp(p1, p2, l2) == 0) {
  82.                 ret = 1 + s1->stlen - l1;
  83.                 break;
  84.             }
  85.             l1--;
  86.             p1++;
  87.         }
  88.     } else {
  89.         while (l1) {
  90.             if (STREQN(p1, p2, l2)) {
  91.                 ret = 1 + s1->stlen - l1;
  92.                 break;
  93.             }
  94.             l1--;
  95.             p1++;
  96.         }
  97.     }
  98.     free_temp(s1);
  99.     free_temp(s2);
  100.     return tmp_number((AWKNUM) ret);
  101. }
  102.  
  103. NODE *
  104. do_int(tree)
  105. NODE *tree;
  106. {
  107.     NODE *tmp;
  108.     double floor();
  109.     double d;
  110.  
  111.     get_one(tree, &tmp);
  112.     d = floor((double)force_number(tmp));
  113.     free_temp(tmp);
  114.     return tmp_number((AWKNUM) d);
  115. }
  116.  
  117. NODE *
  118. do_length(tree)
  119. NODE *tree;
  120. {
  121.     NODE *tmp;
  122.     int len;
  123.  
  124.     get_one(tree, &tmp);
  125.     len = force_string(tmp)->stlen;
  126.     free_temp(tmp);
  127.     return tmp_number((AWKNUM) len);
  128. }
  129.  
  130. NODE *
  131. do_log(tree)
  132. NODE *tree;
  133. {
  134.     NODE *tmp;
  135.     double log();
  136.     double d, arg;
  137.  
  138.     get_one(tree, &tmp);
  139.     arg = (double) force_number(tmp);
  140.     if (arg < 0.0)
  141.         warning("log called with negative argument %g", arg);
  142.     d = log(arg);
  143.     free_temp(tmp);
  144.     return tmp_number((AWKNUM) d);
  145. }
  146.  
  147. /*
  148.  * Note that the output buffer cannot be static because sprintf may get
  149.  * called recursively by force_string.  Hence the wasteful alloca calls 
  150.  */
  151.  
  152. /* %e and %f formats are not properly implemented.  Someone should fix them */
  153. NODE *
  154. do_sprintf(tree)
  155. NODE *tree;
  156. {
  157. #define bchunk(s,l) if(l) {\
  158.     while((l)>ofre) {\
  159.       char *tmp;\
  160.       tmp=(char *)alloca(osiz*2);\
  161.       memcpy(tmp,obuf,olen);\
  162.       obuf=tmp;\
  163.       ofre+=osiz;\
  164.       osiz*=2;\
  165.     }\
  166.     memcpy(obuf+olen,s,(l));\
  167.     olen+=(l);\
  168.     ofre-=(l);\
  169.   }
  170.  
  171.     /* Is there space for something L big in the buffer? */
  172. #define chksize(l)  if((l)>ofre) {\
  173.     char *tmp;\
  174.     tmp=(char *)alloca(osiz*2);\
  175.     memcpy(tmp,obuf,olen);\
  176.     obuf=tmp;\
  177.     ofre+=osiz;\
  178.     osiz*=2;\
  179.   }
  180.  
  181.     /*
  182.      * Get the next arg to be formatted.  If we've run out of args,
  183.      * return "" (Null string) 
  184.      */
  185. #define parse_next_arg() {\
  186.   if(!carg) arg= Nnull_string;\
  187.   else {\
  188.       get_one(carg,&arg);\
  189.     carg=carg->rnode;\
  190.   }\
  191.  }
  192.  
  193.     char *obuf;
  194.     int osiz, ofre, olen;
  195.     static char chbuf[] = "0123456789abcdef";
  196.     static char sp[] = " ";
  197.     char *s0, *s1;
  198.     int n0;
  199.     NODE *sfmt, *arg;
  200.     register NODE *carg;
  201.     long fw, prec, lj, alt, big;
  202.     long *cur;
  203.     long val;
  204. #ifdef sun386            /* Can't cast unsigned (int/long) from ptr->value */
  205.     long tmp_uval;        /* on 386i 4.0.1 C compiler -- it just hangs */
  206. #endif
  207.     unsigned long uval;
  208.     int sgn;
  209.     int base;
  210.     char cpbuf[30];        /* if we have numbers bigger than 30 */
  211.     char *cend = &cpbuf[30];/* chars, we lose, but seems unlikely */
  212.     char *cp;
  213.     char *fill;
  214.     double tmpval;
  215.     char *pr_str;
  216.     int ucasehex = 0;
  217.     extern char *gcvt();
  218.  
  219.  
  220.     obuf = (char *) alloca(120);
  221.     osiz = 120;
  222.     ofre = osiz;
  223.     olen = 0;
  224.     get_one(tree, &sfmt);
  225.     sfmt = force_string(sfmt);
  226.     carg = tree->rnode;
  227.     for (s0 = s1 = sfmt->stptr, n0 = sfmt->stlen; n0-- > 0;) {
  228.         if (*s1 != '%') {
  229.             s1++;
  230.             continue;
  231.         }
  232.         bchunk(s0, s1 - s0);
  233.         s0 = s1;
  234.         cur = &fw;
  235.         fw = 0;
  236.         prec = 0;
  237.         lj = alt = big = 0;
  238.         fill = sp;
  239.         cp = cend;
  240.         s1++;
  241.  
  242. retry:
  243.         --n0;
  244.         switch (*s1++) {
  245.         case '%':
  246.             bchunk("%", 1);
  247.             s0 = s1;
  248.             break;
  249.  
  250.         case '0':
  251.             if (fill != sp || lj)
  252.                 goto lose;
  253.             if (cur == &fw)
  254.                 fill = "0";    /* FALL through */
  255.         case '1':
  256.         case '2':
  257.         case '3':
  258.         case '4':
  259.         case '5':
  260.         case '6':
  261.         case '7':
  262.         case '8':
  263.         case '9':
  264.             if (cur == 0)
  265.                 goto lose;
  266.             *cur = s1[-1] - '0';
  267.             while (n0 > 0 && *s1 >= '0' && *s1 <= '9') {
  268.                 --n0;
  269.                 *cur = *cur * 10 + *s1++ - '0';
  270.             }
  271.             goto retry;
  272. #ifdef not_yet
  273.         case ' ':        /* print ' ' or '-' */
  274.         case '+':        /* print '+' or '-' */
  275. #endif
  276.         case '-':
  277.             if (lj || fill != sp)
  278.                 goto lose;
  279.             lj++;
  280.             goto retry;
  281.         case '.':
  282.             if (cur != &fw)
  283.                 goto lose;
  284.             cur = ≺
  285.             goto retry;
  286.         case '#':
  287.             if (alt)
  288.                 goto lose;
  289.             alt++;
  290.             goto retry;
  291.         case 'l':
  292.             if (big)
  293.                 goto lose;
  294.             big++;
  295.             goto retry;
  296.         case 'c':
  297.             parse_next_arg();
  298.             if (arg->flags & NUMERIC) {
  299. #ifdef sun386
  300.                 tmp_uval = arg->numbr; 
  301.                 uval= (unsigned long) tmp_uval;
  302. #else
  303.                 uval = (unsigned long) arg->numbr;
  304. #endif
  305.                 cpbuf[0] = uval;
  306.                 prec = 1;
  307.                 pr_str = cpbuf;
  308.                 goto dopr_string;
  309.             }
  310.             if (! prec)
  311.                 prec = 1;
  312.             else if (prec > arg->stlen)
  313.                 prec = arg->stlen;
  314.             pr_str = arg->stptr;
  315.             goto dopr_string;
  316.         case 's':
  317.             parse_next_arg();
  318.             arg = force_string(arg);
  319.             if (!prec || prec > arg->stlen)
  320.                 prec = arg->stlen;
  321.             pr_str = arg->stptr;
  322.  
  323.     dopr_string:
  324.             if (fw > prec && !lj) {
  325.                 while (fw > prec) {
  326.                     bchunk(sp, 1);
  327.                     fw--;
  328.                 }
  329.             }
  330.             bchunk(pr_str, (int) prec);
  331.             if (fw > prec) {
  332.                 while (fw > prec) {
  333.                     bchunk(sp, 1);
  334.                     fw--;
  335.                 }
  336.             }
  337.             s0 = s1;
  338.             free_temp(arg);
  339.             break;
  340.         case 'd':
  341.         case 'i':
  342.             parse_next_arg();
  343.             val = (long) force_number(arg);
  344.             free_temp(arg);
  345.             if (val < 0) {
  346.                 sgn = 1;
  347.                 val = -val;
  348.             } else
  349.                 sgn = 0;
  350.             do {
  351.                 *--cp = '0' + val % 10;
  352.                 val /= 10;
  353.             } while (val);
  354.             if (sgn)
  355.                 *--cp = '-';
  356.             if (prec > fw)
  357.                 fw = prec;
  358.             prec = cend - cp;
  359.             if (fw > prec && !lj) {
  360.                 if (fill != sp && *cp == '-') {
  361.                     bchunk(cp, 1);
  362.                     cp++;
  363.                     prec--;
  364.                     fw--;
  365.                 }
  366.                 while (fw > prec) {
  367.                     bchunk(fill, 1);
  368.                     fw--;
  369.                 }
  370.             }
  371.             bchunk(cp, (int) prec);
  372.             if (fw > prec) {
  373.                 while (fw > prec) {
  374.                     bchunk(fill, 1);
  375.                     fw--;
  376.                 }
  377.             }
  378.             s0 = s1;
  379.             break;
  380.         case 'u':
  381.             base = 10;
  382.             goto pr_unsigned;
  383.         case 'o':
  384.             base = 8;
  385.             goto pr_unsigned;
  386.         case 'X':
  387.             ucasehex = 1;
  388.         case 'x':
  389.             base = 16;
  390.             goto pr_unsigned;
  391.     pr_unsigned:
  392.             parse_next_arg();
  393.             uval = (unsigned long) force_number(arg);
  394.             free_temp(arg);
  395.             do {
  396.                 *--cp = chbuf[uval % base];
  397.                 if (ucasehex && isalpha(*cp))
  398.                     *cp = toupper(*cp);
  399.                 uval /= base;
  400.             } while (uval);
  401.             if (alt && (base == 8 || base == 16)) {
  402.                 if (base == 16) {
  403.                     if (ucasehex)
  404.                         *--cp = 'X';
  405.                     else
  406.                         *--cp = 'x';
  407.                 }
  408.                 *--cp = '0';
  409.             }
  410.             prec = cend - cp;
  411.             if (fw > prec && !lj) {
  412.                 while (fw > prec) {
  413.                     bchunk(fill, 1);
  414.                     fw--;
  415.                 }
  416.             }
  417.             bchunk(cp, (int) prec);
  418.             if (fw > prec) {
  419.                 while (fw > prec) {
  420.                     bchunk(fill, 1);
  421.                     fw--;
  422.                 }
  423.             }
  424.             s0 = s1;
  425.             break;
  426.         case 'g':
  427.             parse_next_arg();
  428.             tmpval = force_number(arg);
  429.             free_temp(arg);
  430.             if (prec == 0)
  431.                 prec = 13;
  432.             (void) gcvt(tmpval, (int) prec, cpbuf);
  433.             prec = strlen(cpbuf);
  434.             cp = cpbuf;
  435.             if (fw > prec && !lj) {
  436.                 if (fill != sp && *cp == '-') {
  437.                     bchunk(cp, 1);
  438.                     cp++;
  439.                     prec--;
  440.                 }    /* Deal with .5 as 0.5 */
  441.                 if (fill == sp && *cp == '.') {
  442.                     --fw;
  443.                     while (--fw >= prec) {
  444.                         bchunk(fill, 1);
  445.                     }
  446.                     bchunk("0", 1);
  447.                 } else
  448.                     while (fw-- > prec)
  449.                         bchunk(fill, 1);
  450.             } else {/* Turn .5 into 0.5 */
  451.                 /* FOO */
  452.                 if (*cp == '.' && fill == sp) {
  453.                     bchunk("0", 1);
  454.                     --fw;
  455.                 }
  456.             }
  457.             bchunk(cp, (int) prec);
  458.             if (fw > prec)
  459.                 while (fw-- > prec)
  460.                     bchunk(fill, 1);
  461.             s0 = s1;
  462.             break;
  463.         case 'f':
  464.             parse_next_arg();
  465.             tmpval = force_number(arg);
  466.             free_temp(arg);
  467.             chksize(fw + prec + 5);    /* 5==slop */
  468.  
  469.             cp = cpbuf;
  470.             *cp++ = '%';
  471.             if (lj)
  472.                 *cp++ = '-';
  473.             if (fill != sp)
  474.                 *cp++ = '0';
  475.             if (cur != &fw) {
  476.                 (void) strcpy(cp, "*.*f");
  477.                 (void) sprintf(obuf + olen, cpbuf, (int) fw, (int) prec, (double) tmpval);
  478.             } else {
  479.                 (void) strcpy(cp, "*f");
  480.                 (void) sprintf(obuf + olen, cpbuf, (int) fw, (double) tmpval);
  481.             }
  482.             ofre -= strlen(obuf + olen);
  483.             olen += strlen(obuf + olen);    /* There may be nulls */
  484.             s0 = s1;
  485.             break;
  486.         case 'e':
  487.             parse_next_arg();
  488.             tmpval = force_number(arg);
  489.             free_temp(arg);
  490.             chksize(fw + prec + 5);    /* 5==slop */
  491.             cp = cpbuf;
  492.             *cp++ = '%';
  493.             if (lj)
  494.                 *cp++ = '-';
  495.             if (fill != sp)
  496.                 *cp++ = '0';
  497.             if (cur != &fw) {
  498.                 (void) strcpy(cp, "*.*e");
  499.                 (void) sprintf(obuf + olen, cpbuf, (int) fw, (int) prec, (double) tmpval);
  500.             } else {
  501.                 (void) strcpy(cp, "*e");
  502.                 (void) sprintf(obuf + olen, cpbuf, (int) fw, (double) tmpval);
  503.             }
  504.             ofre -= strlen(obuf + olen);
  505.             olen += strlen(obuf + olen);    /* There may be nulls */
  506.             s0 = s1;
  507.             break;
  508.  
  509.         default:
  510.     lose:
  511.             break;
  512.         }
  513.     }
  514.     bchunk(s0, s1 - s0);
  515.     free_temp(sfmt);
  516.     return tmp_string(obuf, olen);
  517. }
  518.  
  519. void
  520. do_printf(tree)
  521. NODE *tree;
  522. {
  523.     struct redirect *rp = NULL;
  524.     register FILE *fp = stdout;
  525.     int errflg = 0;        /* not used, sigh */
  526.  
  527.     if (tree->rnode) {
  528.         rp = redirect(tree->rnode, &errflg);
  529.         if (rp)
  530.             fp = rp->fp;
  531.     }
  532.     if (fp)
  533.         print_simple(do_sprintf(tree->lnode), fp);
  534.     if (rp && (rp->flag & RED_NOBUF))
  535.         fflush(fp);
  536. }
  537.  
  538. NODE *
  539. do_sqrt(tree)
  540. NODE *tree;
  541. {
  542.     NODE *tmp;
  543.     double sqrt();
  544.     double d, arg;
  545.  
  546.     get_one(tree, &tmp);
  547.     arg = (double) force_number(tmp);
  548.     if (arg < 0.0)
  549.         warning("sqrt called with negative argument %g", arg);
  550.     d = sqrt(arg);
  551.     free_temp(tmp);
  552.     return tmp_number((AWKNUM) d);
  553. }
  554.  
  555. NODE *
  556. do_substr(tree)
  557. NODE *tree;
  558. {
  559.     NODE *t1, *t2, *t3;
  560.     NODE *r;
  561.     register int indx, length;
  562.  
  563.     t1 = t2 = t3 = NULL;
  564.     length = -1;
  565.     if (get_three(tree, &t1, &t2, &t3) == 3)
  566.         length = (int) force_number(t3);
  567.     indx = (int) force_number(t2) - 1;
  568.     t1 = force_string(t1);
  569.     if (length == -1)
  570.         length = t1->stlen;
  571.     if (indx < 0)
  572.         indx = 0;
  573.     if (indx >= t1->stlen || length <= 0) {
  574.         if (t3)
  575.             free_temp(t3);
  576.         free_temp(t2);
  577.         free_temp(t1);
  578.         return Nnull_string;
  579.     }
  580.     if (indx + length > t1->stlen)
  581.         length = t1->stlen - indx;
  582.     if (t3)
  583.         free_temp(t3);
  584.     free_temp(t2);
  585.     r =  tmp_string(t1->stptr + indx, length);
  586.     free_temp(t1);
  587.     return r;
  588. }
  589.  
  590. NODE *
  591. do_system(tree)
  592. NODE *tree;
  593. {
  594. #if defined(macintosh) || defined(unix) || defined(MSDOS) /* || defined(gnu) */
  595.     NODE *tmp;
  596.     int ret;
  597.  
  598.     (void) flush_io ();    /* so output is synchronous with gawk's */
  599.     get_one(tree, &tmp);
  600.     ret = system(force_string(tmp)->stptr);
  601.     ret = (ret >> 8) & 0xff;
  602.     free_temp(tmp);
  603.     return tmp_number((AWKNUM) ret);
  604. #else
  605.     fatal("the \"system\" function is not supported.");
  606.     /* NOTREACHED */
  607. #endif
  608. }
  609.  
  610. void 
  611. do_print(tree)
  612. register NODE *tree;
  613. {
  614.     struct redirect *rp = NULL;
  615.     register FILE *fp = stdout;
  616.     int errflg = 0;        /* not used, sigh */
  617.  
  618.     if (tree->rnode) {
  619.         rp = redirect(tree->rnode, &errflg);
  620.         if (rp)
  621.             fp = rp->fp;
  622.     }
  623.     if (!fp)
  624.         return;
  625.     tree = tree->lnode;
  626.     if (!tree)
  627.         tree = WHOLELINE;
  628.     if (tree->type != Node_expression_list) {
  629.         if (!(tree->flags & STR))
  630.             cant_happen();
  631.         print_simple(tree, fp);
  632.     } else {
  633.         while (tree) {
  634.             print_simple(force_string(tree_eval(tree->lnode)), fp);
  635.             tree = tree->rnode;
  636.             if (tree)
  637.                 print_simple(OFS_node->var_value, fp);
  638.         }
  639.     }
  640.     print_simple(ORS_node->var_value, fp);
  641.     if (rp && (rp->flag & RED_NOBUF))
  642.         fflush(fp);
  643. }
  644.  
  645. NODE *
  646. do_tolower(tree)
  647. NODE *tree;
  648. {
  649.     NODE *t1, *t2;
  650.     register char *cp, *cp2;
  651.  
  652.     get_one(tree, &t1);
  653.     t1 = force_string(t1);
  654.     t2 = tmp_string(t1->stptr, t1->stlen);
  655.     for (cp = t2->stptr, cp2 = t2->stptr + t2->stlen; cp < cp2; cp++)
  656.         if (isupper(*cp))
  657.             *cp = tolower(*cp);
  658.     free_temp(t1);
  659.     return t2;
  660. }
  661.  
  662. NODE *
  663. do_toupper(tree)
  664. NODE *tree;
  665. {
  666.     NODE *t1, *t2;
  667.     register char *cp;
  668.  
  669.     get_one(tree, &t1);
  670.     t1 = force_string(t1);
  671.     t2 = tmp_string(t1->stptr, t1->stlen);
  672.     for (cp = t2->stptr; cp < t2->stptr + t2->stlen; cp++)
  673.         if (islower(*cp))
  674.             *cp = toupper(*cp);
  675.     free_temp(t1);
  676.     return t2;
  677. }
  678.  
  679. /*
  680.  * Get the arguments to functions.  No function cares if you give it too many
  681.  * args (they're ignored).  Only a few fuctions complain about being given
  682.  * too few args.  The rest have defaults.
  683.  */
  684.  
  685. static void
  686. get_one(tree, res)
  687. NODE *tree, **res;
  688. {
  689.     if (!tree) {
  690.         *res = WHOLELINE;
  691.         return;
  692.     }
  693.     *res = tree_eval(tree->lnode);
  694. }
  695.  
  696. static void
  697. get_two(tree, res1, res2)
  698. NODE *tree, **res1, **res2;
  699. {
  700.     if (!tree) {
  701.         *res1 = WHOLELINE;
  702.         return;
  703.     }
  704.     *res1 = tree_eval(tree->lnode);
  705.     if (!tree->rnode)
  706.         return;
  707.     tree = tree->rnode;
  708.     *res2 = tree_eval(tree->lnode);
  709. }
  710.  
  711. static int
  712. get_three(tree, res1, res2, res3)
  713. NODE *tree, **res1, **res2, **res3;
  714. {
  715.     if (!tree) {
  716.         *res1 = WHOLELINE;
  717.         return 0;
  718.     }
  719.     *res1 = tree_eval(tree->lnode);
  720.     if (!tree->rnode)
  721.         return 1;
  722.     tree = tree->rnode;
  723.     *res2 = tree_eval(tree->lnode);
  724.     if (!tree->rnode)
  725.         return 2;
  726.     tree = tree->rnode;
  727.     *res3 = tree_eval(tree->lnode);
  728.     return 3;
  729. }
  730.  
  731. int
  732. a_get_three(tree, res1, res2, res3)
  733. NODE *tree, **res1, **res2, **res3;
  734. {
  735.     if (!tree) {
  736.         *res1 = WHOLELINE;
  737.         return 0;
  738.     }
  739.     *res1 = tree_eval(tree->lnode);
  740.     if (!tree->rnode)
  741.         return 1;
  742.     tree = tree->rnode;
  743.     *res2 = tree->lnode;
  744.     if (!tree->rnode)
  745.         return 2;
  746.     tree = tree->rnode;
  747.     *res3 = tree_eval(tree->lnode);
  748.     return 3;
  749. }
  750.  
  751. void
  752. print_simple(tree, fp)
  753. NODE *tree;
  754. FILE *fp;
  755. {
  756.     if (fwrite(tree->stptr, sizeof(char), tree->stlen, fp) != tree->stlen)
  757.         warning("fwrite: %s", strerror(errno));
  758.     free_temp(tree);
  759. }
  760.  
  761. NODE *
  762. do_atan2(tree)
  763. NODE *tree;
  764. {
  765.     NODE *t1, *t2;
  766.     extern double atan2();
  767.     double d1, d2;
  768.  
  769.     get_two(tree, &t1, &t2);
  770.     d1 = force_number(t1);
  771.     d2 = force_number(t2);
  772.     free_temp(t1);
  773.     free_temp(t2);
  774.     return tmp_number((AWKNUM) atan2(d1, d2));
  775. }
  776.  
  777. NODE *
  778. do_sin(tree)
  779. NODE *tree;
  780. {
  781.     NODE *tmp;
  782.     extern double sin();
  783.     double d;
  784.  
  785.     get_one(tree, &tmp);
  786.     d = sin((double)force_number(tmp));
  787.     free_temp(tmp);
  788.     return tmp_number((AWKNUM) d);
  789. }
  790.  
  791. NODE *
  792. do_cos(tree)
  793. NODE *tree;
  794. {
  795.     NODE *tmp;
  796.     extern double cos();
  797.     double d;
  798.  
  799.     get_one(tree, &tmp);
  800.     d = cos((double)force_number(tmp));
  801.     free_temp(tmp);
  802.     return tmp_number((AWKNUM) d);
  803. }
  804.  
  805. static int firstrand = 1;
  806. static char state[256];
  807.  
  808. #define    MAXLONG    2147483647    /* maximum value for long int */
  809.  
  810. /* ARGSUSED */
  811. #if !defined(macintosh) || defined(mpwgcc)
  812. NODE *
  813. do_rand(tree)
  814. NODE *tree;
  815. #else
  816. NODE *
  817. do_rand(NODE *)
  818. #endif
  819. {
  820.     if (firstrand) {
  821.         (void) initstate((unsigned) 1, state, sizeof state);
  822.         srandom(1);
  823.         firstrand = 0;
  824.     }
  825.     return tmp_number((AWKNUM) random() / MAXLONG);
  826. }
  827.  
  828. NODE *
  829. do_srand(tree)
  830. NODE *tree;
  831. {
  832.     NODE *tmp;
  833.     static long save_seed = 1;
  834.     long ret = save_seed;    /* SVR4 awk srand returns previous seed */
  835. #ifndef macintosh
  836.     extern long time();
  837. #endif
  838.  
  839.     if (firstrand)
  840.         (void) initstate((unsigned) 1, state, sizeof state);
  841.     else
  842.         (void) setstate(state);
  843.  
  844.     if (!tree)
  845.         srandom((int) (save_seed = time(NULL)));
  846.     else {
  847.         get_one(tree, &tmp);
  848.         srandom((int) (save_seed = (long) force_number(tmp)));
  849.         free_temp(tmp);
  850.     }
  851.     firstrand = 0;
  852.     return tmp_number((AWKNUM) ret);
  853. }
  854.  
  855. NODE *
  856. do_match(tree)
  857. NODE *tree;
  858. {
  859.     NODE *t1;
  860.     int rstart;
  861.     struct re_registers reregs;
  862.     struct re_pattern_buffer *rp;
  863.     int need_to_free = 0;
  864.  
  865.     t1 = force_string(tree_eval(tree->lnode));
  866.     tree = tree->rnode;
  867.     if (tree == NULL || tree->lnode == NULL)
  868.         fatal("match called with only one argument");
  869.     tree = tree->lnode;
  870.     if (tree->type == Node_regex) {
  871.         rp = tree->rereg;
  872.         if (!strict && ((IGNORECASE_node->var_value->numbr != 0)
  873.             ^ (tree->re_case != 0))) {
  874.             /* recompile since case sensitivity differs */
  875.             rp = tree->rereg =
  876.                 mk_re_parse(tree->re_text,
  877.                 (IGNORECASE_node->var_value->numbr != 0));
  878.             tree->re_case =
  879.                 (IGNORECASE_node->var_value->numbr != 0);
  880.         }
  881.     } else {
  882.         need_to_free = 1;
  883.         rp = make_regexp(force_string(tree_eval(tree)),
  884.                 (IGNORECASE_node->var_value->numbr != 0));
  885.         if (rp == NULL)
  886.             cant_happen();
  887.     }
  888.     rstart = re_search(rp, t1->stptr, t1->stlen, 0, t1->stlen, &reregs);
  889.     free_temp(t1);
  890.     if (rstart >= 0) {
  891.         rstart++;    /* 1-based indexing */
  892.         /* RSTART set to rstart below */
  893.         RLENGTH_node->var_value->numbr =
  894.             (AWKNUM) (reregs.end[0] - reregs.start[0]);
  895.     } else {
  896.         /*
  897.          * Match failed. Set RSTART to 0, RLENGTH to -1.
  898.          * Return the value of RSTART.
  899.          */
  900.         rstart = 0;    /* used as return value */
  901.         RLENGTH_node->var_value->numbr = -1.0;
  902.     }
  903.     RSTART_node->var_value->numbr = (AWKNUM) rstart;
  904.     if (need_to_free) {
  905.         free(rp->buffer);
  906.         free(rp->fastmap);
  907.         free((char *) rp);
  908.     }
  909.     return tmp_number((AWKNUM) rstart);
  910. }
  911.  
  912. static NODE *
  913. sub_common(tree, global)
  914. NODE *tree;
  915. int global;
  916. {
  917.     register int len;
  918.     register char *scan;
  919.     register char *bp, *cp;
  920.     int search_start = 0;
  921.     int match_length;
  922.     int matches = 0;
  923.     char *buf;
  924.     struct re_pattern_buffer *rp;
  925.     NODE *s;        /* subst. pattern */
  926.     NODE *t;        /* string to make sub. in; $0 if none given */
  927.     struct re_registers reregs;
  928.     unsigned int saveflags;
  929.     NODE *tmp;
  930.     NODE **lhs;
  931.     char *lastbuf;
  932.     int need_to_free = 0;
  933.  
  934.     if (tree == NULL)
  935.         fatal("sub or gsub called with 0 arguments");
  936.     tmp = tree->lnode;
  937.     if (tmp->type == Node_regex) {
  938.         rp = tmp->rereg;
  939.         if (! strict && ((IGNORECASE_node->var_value->numbr != 0)
  940.             ^ (tmp->re_case != 0))) {
  941.             /* recompile since case sensitivity differs */
  942.             rp = tmp->rereg =
  943.                 mk_re_parse(tmp->re_text,
  944.                 (IGNORECASE_node->var_value->numbr != 0));
  945.             tmp->re_case = (IGNORECASE_node->var_value->numbr != 0);
  946.         }
  947.     } else {
  948.         need_to_free = 1;
  949.         rp = make_regexp(force_string(tree_eval(tmp)),
  950.                 (IGNORECASE_node->var_value->numbr != 0));
  951.         if (rp == NULL)
  952.             cant_happen();
  953.     }
  954.     tree = tree->rnode;
  955.     if (tree == NULL)
  956.         fatal("sub or gsub called with only 1 argument");
  957.     s = force_string(tree_eval(tree->lnode));
  958.     tree = tree->rnode;
  959.     deref = 0;
  960.     field_num = -1;
  961.     if (tree == NULL) {
  962.         t = node0_valid ? fields_arr[0] : *get_field(0, 0);
  963.         lhs = &fields_arr[0];
  964.         field_num = 0;
  965.         deref = t;
  966.     } else {
  967.         t = tree->lnode;
  968.         lhs = get_lhs(t, 1);
  969.         t = force_string(tree_eval(t));
  970.     }
  971.     /*
  972.      * create a private copy of the string
  973.      */
  974.     if (t->stref > 1 || (t->flags & PERM)) {
  975.         saveflags = t->flags;
  976.         t->flags &= ~MALLOC;
  977.         tmp = dupnode(t);
  978.         t->flags = saveflags;
  979.         do_deref();
  980.         t = tmp;
  981.         if (lhs)
  982.             *lhs = tmp;
  983.     }
  984.     lastbuf = t->stptr;
  985.     do {
  986.         if (re_search(rp, t->stptr, t->stlen, search_start,
  987.             t->stlen-search_start, &reregs) == -1
  988.             || reregs.start[0] == reregs.end[0])
  989.             break;
  990.         matches++;
  991.  
  992.         /*
  993.          * first, make a pass through the sub. pattern, to calculate
  994.          * the length of the string after substitution 
  995.          */
  996.         match_length = reregs.end[0] - reregs.start[0];
  997.         len = t->stlen - match_length;
  998.         for (scan = s->stptr; scan < s->stptr + s->stlen; scan++)
  999.             if (*scan == '&')
  1000.                 len += match_length;
  1001.             else if (*scan == '\\' && *(scan+1) == '&') {
  1002.                 scan++;
  1003.                 len++;
  1004.             } else
  1005.                 len++;
  1006.         emalloc(buf, char *, len + 1, "do_sub");
  1007.         bp = buf;
  1008.  
  1009.         /*
  1010.          * now, create the result, copying in parts of the original
  1011.          * string 
  1012.          */
  1013.         for (scan = t->stptr; scan < t->stptr + reregs.start[0]; scan++)
  1014.             *bp++ = *scan;
  1015.         for (scan = s->stptr; scan < s->stptr + s->stlen; scan++)
  1016.             if (*scan == '&')
  1017.                 for (cp = t->stptr + reregs.start[0];
  1018.                      cp < t->stptr + reregs.end[0]; cp++)
  1019.                     *bp++ = *cp;
  1020.             else if (*scan == '\\' && *(scan+1) == '&') {
  1021.                 scan++;
  1022.                 *bp++ = *scan;
  1023.             } else
  1024.                 *bp++ = *scan;
  1025.         search_start = bp - buf;
  1026.         for (scan = t->stptr + reregs.end[0];
  1027.              scan < t->stptr + t->stlen; scan++)
  1028.             *bp++ = *scan;
  1029.         *bp = '\0';
  1030.         free(lastbuf);
  1031.         t->stptr = buf;
  1032.         lastbuf = buf;
  1033.         t->stlen = len;
  1034.     } while (global && search_start < t->stlen);
  1035.  
  1036.     free_temp(s);
  1037.     if (need_to_free) {
  1038.         free(rp->buffer);
  1039.         free(rp->fastmap);
  1040.         free((char *) rp);
  1041.     }
  1042.     if (matches > 0) {
  1043.         if (field_num == 0)
  1044.             set_record(fields_arr[0]->stptr, fields_arr[0]->stlen);
  1045.         t->flags &= ~(NUM|NUMERIC);
  1046.     }
  1047.     field_num = -1;
  1048.     return tmp_number((AWKNUM) matches);
  1049. }
  1050.  
  1051. NODE *
  1052. do_gsub(tree)
  1053. NODE *tree;
  1054. {
  1055.     return sub_common(tree, 1);
  1056. }
  1057.  
  1058. NODE *
  1059. do_sub(tree)
  1060. NODE *tree;
  1061. {
  1062.     return sub_common(tree, 0);
  1063. }
  1064.  
  1065.